package com.sg.common.dao;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javassist.expr.NewArray;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.apache.bcel.generic.NEW;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONArray;
import com.sg.common.utils.CollUtil;
import com.sg.common.utils.Constant;
import com.sg.common.utils.ReUtils;

@Component
@Transactional
public class BaseDao {

	@Resource
	SessionFactory sessionFactory;

	public Session getSession() {
		// return sessionFactory.openSession();
		return sessionFactory.getCurrentSession();
	}

	public <T> T get(Class<T> entityClass, Serializable primaryKey) {

		return (T) getSession().get(entityClass, primaryKey);
	}

	public <T> T get(String entityName, Serializable primaryKey) {

		return (T) getSession().get(entityName, primaryKey);
	}

	@Transactional
	public void update(Object obj) {
		getSession().merge(obj);
	}

	@Transactional
	public void update(String entityName, Object obj) {
		getSession().merge(entityName, obj);
	}

	@Transactional
	public void updateMap(Object obj) throws IllegalAccessException,
			InvocationTargetException, NoSuchMethodException {
		getSession().merge(ReUtils.getStr(obj, Constant.BEAN_TYPE), obj);
	}

	@Transactional
	public void updateList(List<?> objs) {
		for (Object obj : objs)
			getSession().merge(obj);
	}

	@Transactional
	public void saveList(List<?> objs) {
		for (Object obj : objs)
			getSession().persist(obj);
	}

	@Transactional
	public void save(String entityName, Object obj) {
		getSession().persist(entityName, obj);
	}

	@Transactional
	public void save(Object obj) {
		getSession().persist(obj);
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> query(String sql, T bean) {
		Query cq = getSession().createQuery(sql);
		List<T> resultList = cq.list();
		return resultList;

	}

	@SuppressWarnings("unchecked")
	public List<Object> query(String sql) {
		Query cq = getSession().createQuery(sql);
		List<Object> resultList = cq.list();
		return resultList;
	}

	@Deprecated
	@SuppressWarnings("unchecked")
	public List<Object> queryBySql(String sql) {
		SQLQuery cq = getSession().createSQLQuery(sql);
		List<Object> resultList = cq.list();
		return resultList;
	}

	@SuppressWarnings("unchecked")
	public List<Map<String, Object>> queryBySqlToMap(String sql, String[] ms) {
		SQLQuery cq = getSession().createSQLQuery(sql);
		List<Object> resultList = cq.list();
		List<Map<String, Object>> res= new ArrayList<Map<String,Object>>();
		for (Object o : resultList) {
			HashMap<String, Object> map = new HashMap<String, Object>();
			res.add(map);
			int ind = 0;
			Object[] os = (Object[]) o;
			for(Object one:os){
				if (StringUtils.contains(ms[ind], "`")) {
					String[] split = StringUtils.split(ms[ind], "`");
					if (StringUtils.equals(split[0], "array")) {
						if(one!=null&&StringUtils.isNotEmpty(one.toString()))
						{
							JSONArray jsonArray=JSONArray.parseArray(one.toString());
							map.put(split[1], jsonArray.toArray());
						}
						else
						{
							map.put(split[1], new Object[] { });
						}
					}
				}else {
					map.put(ms[ind], one);
				}
				ind++;
			}
		}
		return res;
	}

	@SuppressWarnings("unchecked")
	public List<Map<String, Object>> queryBySqlToMap(String sql, Object[] params, String[] ms) {
		SQLQuery cq = getSession().createSQLQuery(sql);
		if (params != null && params.length > 0) {
			int i = 0;
			for (Object p : params) {
				cq.setParameter(i++, p);
			}
		}
		List<Object> resultList = cq.list();
		List<Map<String, Object>> res= new ArrayList<Map<String,Object>>();
		for (Object o : resultList) {
			LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
			res.add(map);
			int ind = 0;
			Object[] os = (Object[]) o;
			for(Object one:os){
				if (StringUtils.contains(ms[ind], "`")) {
					String[] split = StringUtils.split(ms[ind], "`");
					if (StringUtils.equals(split[0], "array")) {
						if(one!=null&&StringUtils.isNotEmpty(one.toString()))
						{
							JSONArray jsonArray=JSONArray.parseArray(one.toString());
							map.put(split[1], jsonArray.toArray());
						}
						else
						{
							map.put(split[1], new Object[] { });
						}
					}
				}else {
					map.put(ms[ind], one);
				}
				ind++;
			}
		}
		return res;
	}

	@SuppressWarnings("unchecked")
	public List<Object> queryBySql(String sql, Object[] params) {
		SQLQuery cq = getSession().createSQLQuery(sql);
		if (params != null && params.length > 0) {
			int i = 0;
			for (Object p : params) {
				cq.setParameter(i++, p);
			}
		}
		List<Object> resultList = cq.list();
		return resultList;
	}

	public int execute(String sql, Object[] params) {
		Query cq = getSession().createQuery(sql);
		if (params != null && params.length > 0) {
			int i = 0;
			for (Object p : params) {
				cq.setParameter(i++, p);
			}
		}
		int result = cq.executeUpdate();
		return result;
	}

	public int excuteBySql(String sql) {
		int result;
		SQLQuery query = this.getSession().createSQLQuery(sql);
		result = query.executeUpdate();
		return result;
	}

	public int excuteBySql(String sql, Object[] params) {
		int result;
		SQLQuery query = this.getSession().createSQLQuery(sql);
		if (params != null && params.length > 0) {
			int i = 0;
			for (Object p : params) {
				query.setParameter(i++, p);
			}
		}
		result = query.executeUpdate();
		return result;
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> find(DetachedCriteria dc) {
		// em.createQuery(criteriaQuery)
		// System.out.print(1);
		List<T> list = dc.getExecutableCriteria(getSession()).list();
		return list;
	}

	/**
	 * 保存或修改实便
	 * 
	 * @param <T>
	 */
	@Transactional
	public <T> void saveOrUpdate(T oTO) {
		// getSession().saveOrUpdate(oTO);
		getSession().persist(oTO);
	}

	/**
	 * 删除实例
	 */
	@Transactional
	public <T> void delete(T oTO) {
		getSession().delete(oTO);
	}

	/**
	 * 删除实例
	 */
	@Transactional
	public <T> void delete(String entityName, T oTO) {
		getSession().delete(entityName, oTO);
	}

	@Transactional
	public <T> void deleteList(List<?> objs) {
		for (Object obj : objs)
			getSession().delete(obj);
	}

	/**
	 * 取得丿ت实例
	 */
	// @SuppressWarnings("unchecked")
	// public <T> T get(Class<T> clazz, Serializable id) {
	// return (T) getSession().get(clazz, id);
	// }

	/**
	 * DetachedCriteria方式查询
	 * 
	 * @param <T>
	 */
	public int findCount(final DetachedCriteria dc) {
		Criteria criteria = dc.getExecutableCriteria(getSession());
		criteria.setProjection(Projections.rowCount());
		Object uniqueResult = criteria.uniqueResult();// .list();
		return ((Long) uniqueResult).intValue();
	}

	/**
	 * DetachedCriteria方式查询
	 * 
	 * @param <T>
	 */
	public int findMax(final DetachedCriteria dc, final String property) {
		Criteria criteria = dc.getExecutableCriteria(getSession());
		criteria.setProjection(Projections.max(property));
		return ((Long) criteria.uniqueResult()).intValue();
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> findWithPage2(final DetachedCriteria dc,
			final int first, final int rows) {
		// List<T> findByCriteria = getHibernateTemplate().findByCriteria(dc,
		// first, rows);
		return dc.getExecutableCriteria(getSession()).setFirstResult(first)
				.setMaxResults(rows).list();
		// return findByCriteria;
	}

	public <T> T findBean(DetachedCriteria dc) {
		List<T> find = find(dc);
		if (CollUtil.isNotEmpty(find)) {
			return find.get(0);
		}
		return null;
	}

	public <T> List<T> get(Class<T> clazz) {
		DetachedCriteria dc = DetachedCriteria.forClass(clazz);
		return find(dc);
	}
}